/****************************************
*
*	EoSC_Pawn
*	
*	Represents the player.
*
*	ToDo:
*	Needs to be archetypable.
*	Adjust Player speed.
*	Set up Pawn correctly.
*
****************************************/

class EoSC_Pawn extends UDKPawn
	HideCategories(Movement, AI, Camera, Debug, Attachment, Physics, Advanced, Object);

// Light environment for our pawn
var(Pawn) const LightEnvironmentComponent LightEnvironment;
// var(Camera) float ViewPitchMin;
// var(Camera) float ViewPitchMax;
// Weapon socket name to attach weapons to
var(Pawn) const Name WeaponSocketName;
// Aim Offset Anim Node name
var(Pawn) const Name AimNodeName;
// Gun recoil skeletal controller
var(Pawn) const Name RecoilSkelControlName;
// Explosion sound to play when the pawn has died
var(Pawn) const SoundCue ExplosionSoundCue;
// Explosion particle effect to play when the pawn has died
var(Pawn) const ParticleSystem ExplosionParticleTemplate;
// Sound to play when the pawn gets hit
var(Pawn) const array<SoundCue> HitSoundCues;
// Sound to play when the pawn dies
var(Pawn) const array<SoundCue> DeathSoundCues;
// Current weapon archetype used for attachment purposes
var RepNotify EoSC_Weapon WeaponAttachmentArchetype;
// Reference to the AimOffset node in the AnimTree
var ProtectedWrite transient AnimNodeAimOffset AnimNodeAimOffset;
// Reference to the Gun recoil skeletal controller in the AnimTree
var ProtectedWrite transient GameSkelCtrl_Recoil RecoilSkelControl;
// Current weapon attachment
var ProtectedWrite transient EoSC_Weapon WeaponAttachment;

// Replication block
replication
{
	if (bNetDirty && !bNetOwner && Role == Role_Authority)
		WeaponAttachmentArchetype;
}

// We are adding the default inventory.
function AddDefaultInventory()
{
	InvManager.CreateInventory(class'EoSCelest.EoSC_Handgun');
}

/**
 * Called when the pawn takes damage
 *
 * @param		Damage				How much damage was done
 * @param		InstigatedBy		Controller that did the damage
 * @param		HitLocation			Where in the world damage was done
 * @param		Momentum			Momentum transferred by the hit
 * @param		DamageType			What type of damage was inflicted
 * @param		HitInfo				Extra information about the hit
 * @param		DamageCauser		Actual actor that did the damage
 * @network							Server and client
 */
simulated event TakeDamage(int Damage, Controller InstigatedBy, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser)
{
	Super.TakeDamage(Damage, InstigatedBy, HitLocation, Momentum, DamageType, HitInfo, DamageCauser);

	// Play a pain sound
	if (Health > 0 && HitSoundCues.Length > 0)
	{
		PlaySound(HitSoundCues[Rand(HitSoundCues.Length)], true);
	}
}

/**
 * This pawn has died.
 *
 * @param		Killer				Who killed this pawn
 * @param		DamageType			What killed it
 * @param		HitLocation			Where did the hit occur
 * @return							Return true if allowed
 */
simulated function PlayDying(class<DamageType> DamageType, vector HitLoc)
{
	Super.PlayDying(DamageType, HitLoc);

	// Play a death sound
	if (DeathSoundCues.Length > 0)
	{
		PlaySound(DeathSoundCues[Rand(DeathSoundCues.Length)], true);
	}

	// Play the explosion sound 
	if (ExplosionSoundCue != None)
	{
		PlaySound(ExplosionSoundCue, true);
	}

	// Spawn the explosion particle effect
	if (WorldInfo.NetMode != NM_DedicatedServer && WorldInfo.MyEmitterPool != None && ExplosionParticleTemplate != None)
	{
		WorldInfo.MyEmitterPool.SpawnEmitter(ExplosionParticleTemplate, Location);
	}

	// Hide the pawn
	SetHidden(true);
}

/**
 * Called when a variable flagged with rep notify is replicated
 *
 * @param			VarName				Name of the variable that was replicated
 * @network								Server and client
 */
simulated event ReplicatedEvent(Name VarName)
{
	// Weapon attachment archetype was replicated, update the weapon attachment
	if (VarName == NameOf(WeaponAttachmentArchetype))
	{
		UpdateWeaponAttachment();
	}

	Super.ReplicatedEvent(VarName);
}

/**
 * Called by ReplicatedEvent when WeaponAttachmentArchetype has been replicated
 *
 * @network			Server and client
 */
simulated function UpdateWeaponAttachment()
{
	// Ensure that the weapon attachment archetype is not none
	if (WeaponAttachmentArchetype == None)
	{
		return;
	}

	// If there was a weapon attachment before, destroy it now
	if (WeaponAttachment != None)
	{
		WeaponAttachment.Destroy();
	}

	// Spawn the weapon attachment
	WeaponAttachment = Spawn(WeaponAttachmentArchetype.Class,,,,, WeaponAttachmentArchetype);
	if (WeaponAttachment != None)
	{
		// Attach the weapon to myself
		WeaponAttachment.AttachToPawn(Self);
		// Set the weapon attachments instigator
		WeaponAttachment.Instigator = Self;
	}
}

/**
 * Called when the pawn is destroyed
 *
 * @network			Server and client
 */
simulated event Destroyed()
{
	Super.Destroyed();

	// Clear anim node object references
	AnimNodeAimOffset = None;
	// Clear skeletal controller object references
	RecoilSkelControl = None;
}

/**
 * Called when the AnimTree has been initialized for a skeletal mesh component
 *
 * @param		SkelComp			Skeletal mesh component that has had its AnimTree initialized
 * @network							Server and client
 */
simulated event PostInitAnimTree(SkeletalMeshComponent SkelComp)
{
	Super.PostInitAnimTree(SkelComp);

	// Only refresh anim nodes if our main mesh was updated
	if (SkelComp == Mesh)
	{
		// Reference the anim node aim offset
		AnimNodeAimOffset = AnimNodeAimOffset(SkelComp.FindAnimNode(AimNodeName));
		// Reference the skel control recoil
		RecoilSkelControl = GameSkelCtrl_Recoil(SkelComp.FindSkelControl(RecoilSkelControlName));
	}
}

/**
 * Called every time the pawn is updated
 *
 * @param		DeltaTime		Time since the last tick
 * @network						Server and client
 */
simulated function Tick(float DeltaTime)
{
	local PlayerController PlayerController;
	local float CurrentPitch;

	Super.Tick(DeltaTime);

	if (AnimNodeAimOffset != None)
	{
		// If player controller is valid then Use local controller pitch
		PlayerController = PlayerController(Controller);
		if (PlayerController != None)
		{
			CurrentPitch = PlayerController.Rotation.Pitch;
		}
		// Otherwise use the remote view pitch value
		else
		{			
			// Remember that the remote view pitch is sent over "compressed", so "uncompress" it here
			CurrentPitch = RemoteViewPitch << 8;
		}

		// "Fix" the current pitch
		if (CurrentPitch > 16384)
		{
			CurrentPitch -= 65536;
		}

		// Update the aim offset
		AnimNodeAimOffset.Aim.Y = FClamp((CurrentPitch / 16384.f), -1.f, 1.f);
	}
}

/**
 * Called when a pawn's weapon has fired and is responsibile for delegating the creation of all of the different effects. bViaReplication denotes if this call in as the result of the flashcount/flashlocation 
 * being replicated. It's used filter out when to make the effects.
 *
 * @param		InWeapon				Weapon that was fired
 * @param		bViaReplication			Function was called because of replication
 * @param		HitLocation				Weapon hit location
 * @network								Server and client
 */
simulated function WeaponFired(Weapon InWeapon, bool bViaReplication, optional vector HitLocation)
{
	local EoSC_Weapon EoSC_Weapon;

	// Figure out which weapon to play the firing effects
	EoSC_Weapon = (Weapon != None) ? EoSC_Weapon(Weapon) : WeaponAttachment;

	// Play the recoil animation if the fire mode has recoil
	if (RecoilSkelControl != None)
	{		
		if (EoSC_Weapon != None && EoSC_Weapon.CurrentFireMode < EoSC_Weapon.FireModes.Length && EoSC_Weapon.FireModes[FiringMode] != None && EoSC_Weapon.FireModes[FiringMode].HasRecoil)
		{
			RecoilSkelControl.bPlayRecoil = true;
		}
	}

	Super.WeaponFired(EoSC_Weapon, bViaReplication, HitLocation);
}

/**
 * Called when a pawn's weapon has stopped firing and is responsibile for delegating the destruction of all of the different effects. bViaReplication denotes if this call in as the result of the flashcount/
 * flashlocation being replicated.
 *
 * @param		InWeapon				Weapon that stopped firing
 * @param		bViaReplication			Function called because of replication
 * @network								Server and client
 */
simulated function WeaponStoppedFiring(Weapon InWeapon, bool bViaReplication)
{
	Super.WeaponStoppedFiring((Weapon != None) ? EoSC_Weapon(Weapon) : WeaponAttachment, bViaReplication);
}

// We are telling the PlayerController that we want the ThirdPerson.
simulated function name GetDefaultCameraMode(PlayerController RequestedBy)
{
	return 'ThirdPerson';
}

defaultproperties
{
	// Camera related settings (needs to be adjustable)
	ViewPitchMin=-8000
	ViewPitchMax=4000

	// Player related settings
	GroundSpeed=300.0

	// Setting our Inventory Manager
	InventoryManagerClass=class'EoSCelest.EoSC_InventoryManager'

	// Remove the Editor Sprite
	Components.Remove(Sprite)

	// Adding the LightEnvironment
	Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
		bSynthesizeSHLight=true
		bIsCharacterLightEnvironment=true
		bUseBooleanEnvironmentShadowing=false
		InvisibleUpdateTime=1.f
		MinTimeBetweenFullUpdates=0.2f
	End Object
	LightEnvironment=MyLightEnvironment
	Components.Add(MyLightEnvironment)

	// Setting the Player Mesh
    Begin Object class=SkeletalMeshComponent Name=SandboxPawnSkeletalMesh
		SkeletalMesh=SkeletalMesh'CH_IronGuard_Male.Mesh.SK_CH_IronGuard_MaleA'
		AnimSets(0)=AnimSet'CH_AnimHuman.Anims.K_AnimHuman_BaseMale'
		AnimTreeTemplate=AnimTree'CH_AnimHuman_Tree.AT_CH_Human'
		HiddenGame=FALSE 
		HiddenEditor=FALSE
		bCacheAnimSequenceNodes=false
		AlwaysLoadOnClient=true
		AlwaysLoadOnServer=true
		CastShadow=true
		BlockRigidBody=true
		bUpdateSkelWhenNotRendered=true
		bIgnoreControllersWhenNotRendered=false
		bUpdateKinematicBonesFromAnimation=true
		bCastDynamicShadow=true
		RBChannel=RBCC_Untitled3
		RBCollideWithChannels=(Untitled3=true)
		LightEnvironment=MyLightEnvironment
		bAcceptsDynamicDecals=false
		bHasPhysicsAssetInstance=true
		TickGroup=TG_PreAsyncWork
		MinDistFactorForKinematicUpdate=0.2f
		bChartDistanceFactor=true
		RBDominanceGroup=20
		bUseOnePassLightingOnTranslucency=true
		bPerBoneMotionBlur=true
    End Object
    Mesh=SandboxPawnSkeletalMesh
    Components.Add(SandboxPawnSkeletalMesh)

	BaseTranslationOffset=6.0

	// Setting up the Player Collision
	Begin Object Name=CollisionCylinder
		CollisionRadius=+0021.000000
		CollisionHeight=+0044.000000
	End Object
	CylinderComponent=CollisionCylinder
}